<template>
  <view :class="[ns.b, disabled && 'is-disabled', ns.b + '--' + type]">
    <view :class="[ns.e('prefix')]">
      <slot name="prefix"></slot>
    </view>
    <view :class="[ns.e('content')]">
      <textarea :class="[ns.e('input')]" v-if="fv.isTextarea" :="fv.inputProps" />
      <input :class="[ns.e('input')]" v-else :="fv.inputProps">
      <view :class="[ns.e('limit')]" v-if="fv.showWordLimit">{{ fv.wordLimitText }}</view>
    </view>
    <view :class="[ns.e('suffix')]">
      <slot name="suffix"></slot>
      <view :="fv.clearableProps" v-if="fv.showClearable"></view>
      <view :="fv.eyeProps" v-if="fv.showEye"></view>
      <Button :="fv.getCodeProps" v-if="fv.showGetCode">
        {{ state.getCodeTime || t('components.input.getCode') }}
      </Button>
    </view>
  </view>
</template>

<script lang="ts" setup>
import { useNamespace } from '@/utils'
import Input from '.'
import { computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
import Button from '@/components/button/index.vue'
import { t } from '@/locale'
import Timer from '@/utils/timer'
import { CatchError } from '@/utils/catch-error'
import { isObject, merge } from 'lodash'

defineOptions({
  name: Input.name,
})
const props = defineProps(Input.props)
const emits = defineEmits(Input.emits)
const ns = useNamespace(Input.name)
const config = {
  getCodeTimer: new Timer('Interval'),
  getCodeCe: new CatchError(),
  offWatch(){}
}
const state = reactive({
  showPassword: false,
  getCodeTime: 0,
  value: props.modelValue
})
const fv = computed(() => {
  const mv = String(props.modelValue ?? '')
  const isPassword = props.type === 'password'
  const showEye = isPassword
  const eyeProps = {
    class: ['iconfont', `icon-${state.showPassword ? 'open' : 'close'}-eye`],
    onClick: () => state.showPassword = !state.showPassword
  }
  const showGetCode = props.type === 'code'
  const getCodeProps = {
    class: ['is-link'],
    onClick: () => {
      config.getCodeCe.run = async () => {
        if (!props.getCode) return console.warn(t('components.input.getCodeFunWarn'))
        if (state.getCodeTime) throw t('components.input.GetCodeFrequent')

        state.getCodeTime = props.getCodeGap - 1
        config.getCodeTimer.run(() => {
          if (!--state.getCodeTime) return config.getCodeTimer.stop()
        }, 1000)
        return props.getCode()
      }
    },
    disabled: Boolean(state.getCodeTime) || props.disabled
  }
  const isTextarea = props.type === 'textarea'
  const inputDc = Input.variables.typeConfig.get(props.type)
  const inputType = isPassword
    ? state.showPassword ? 'text' : 'password'
    : (inputDc?.type ?? props.type)
  const inputProps = merge({}, inputDc, {
    placeholder: props.placeholder,
    value: state.value,
    type: inputType,
    password: isPassword && !state.showPassword,
    disabled: props.disabled,
    onInput: change,
    onFocus: change,
    onBlur: change,
    onTouchmove: (e: Event) => e.stopPropagation(),
    maxlength: 140
  }, props.nativeProps)
  const showClearable = props.clearable && mv.length && !isTextarea
  const clearableProps = {
    class: ['iconfont', 'icon-close'],
    onClick: () => {
      change('')
      emits('clear')
    }
  }
  const showWordLimit = props.showWordLimit
  const wordLimitText = mv.length + (inputProps.maxlength > 1 ? '/' + inputProps.maxlength : '')

  return {
    showEye,
    eyeProps,
    showGetCode,
    getCodeProps,
    showClearable,
    clearableProps,
    isTextarea,
    inputProps,
    mv,
    showWordLimit,
    wordLimitText
  }
})

function change(val: string | Event) {
  if (isObject(val)) {
    const type = val.type.replace(/^(on)?[A-Z]/, str => str.slice(str.length - 1))
    const value = Object(val).detail.value

    emits(type as any, value)
    return change(value)
  }
  
  if (props.modelValue === val) return

  const value = val as string
  emits('update:modelValue', value)
  emits('change', value)
  watchValue()
}
async function watchValue(){
  state.value = ''
  await nextTick()
  state.value = props.modelValue
}
config.offWatch = watch(() => props.modelValue, watchValue)

onBeforeUnmount(() => {
  config.getCodeTimer.stop()
  config.offWatch()
})
</script>